package com.cnap.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.cnap.config.GatewayConfig;
import com.cnap.db.entity.*;
import com.cnap.db.mapper.MicroServiceMapper;
import com.cnap.db.mapper.ScaleStrategyMapper;
import com.cnap.db.mapper.ScheduleStrategyMapper;
import com.cnap.model.application.DeployResourceInfo;
import com.cnap.model.cloud.CloudVmModel;
import com.cnap.model.cloud.CommentResultForCloud;
import com.cnap.model.cloud.CreateCloudParam;
import com.cnap.model.cloud.DeleteIndicatorHistoryParam;
import com.cnap.model.common.PageResult;
import com.cnap.model.common.ResultCode;
import com.cnap.model.exception.JsonException;
import com.cnap.model.intelligent.IntelligentClusterInfo;
import com.cnap.model.intelligent.IntelligentConstants;
import com.cnap.model.intelligent.IntelligentHistoryVO;
import com.cnap.model.intelligent.NotifyClusterInfoDTO;
import com.cnap.model.intelligent.UpdateIntelligentDTO;
import com.cnap.model.schedule.ClusterInfoVO;
import com.cnap.model.schedule.OperateTypeEnum;
import com.cnap.model.schedule.QueryMicroServiceParam;
import com.cnap.model.schedule.UpdateUserChooseParam;
import com.cnap.model.schedule.engine.CommentResultForEngine;
import com.cnap.model.schedule.engine.DeployPolicyCalcResV2;
import com.cnap.model.schedule.engine.DeployPolicyConfigV2;
import com.cnap.model.schedule.engine.DeployPolicyRequestV2;
import com.cnap.model.schedule.engine.OperateReq;
import com.cnap.model.schedule.engine.VmModel;
import com.cnap.model.schedule.engine.alg.AlgDeployClusterInfo;
import com.cnap.model.schedule.engine.alg.ClusterDetail;
import com.cnap.model.schedule.engine.alg.ResourceTypeEnum;
import com.cnap.model.stage.StageTypeEnum;
import com.cnap.model.strategy.DistributeParamV2;
import com.cnap.model.strategy.MicroServiceVOV2;
import com.cnap.model.strategy.StrategyVO;
import com.cnap.model.strategy.SvcConstants;
import com.cnap.model.strategy.scale.ScaleStrategyDTO;
import com.cnap.model.strategy.scale.ScaleStrategyVO;
import com.cnap.model.strategy.schedule.CommonScheduleDTO;
import com.cnap.model.strategy.schedule.ScheduleStrategyDTO;
import com.cnap.model.strategy.schedule.ScheduleStrategyVO;
import com.cnap.model.strategy.schedule.SvcTypeEnum;
import com.cnap.service.*;
import com.cnap.utils.JsonUtil;
import com.cnap.utils.PageUtils;
import com.cnap.utils.TokenUtils;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <类文件描述>
 *
 * @author xc
 **/
@Service
public class StrategyServiceImpl implements StrategyService {
    private static final Logger LOGGER = LoggerFactory.getLogger(StrategyServiceImpl.class);
    private final GatewayConfig gatewayConfig;
    private final AlgorithmEngineService algorithmEngineService;
    private final ClusterInfoService clusterInfoService;
    private final MicroServiceMapper microServiceMapper;
    private final ScaleStrategyMapper scaleStrategyMapper;
    private final ScheduleStrategyMapper scheduleStrategyMapper;
    private final IntelligentScheduleService intelligentScheduleService;
    private final CloudMgmtService cloudMgmtService;
    private final IndicatorService indicatorService;


    @Autowired
    public StrategyServiceImpl(GatewayConfig gatewayConfig, AlgorithmEngineService algorithmEngineService,
                               ClusterInfoService clusterInfoService, MicroServiceMapper microServiceMapper,
                               ScaleStrategyMapper scaleStrategyMapper, ScheduleStrategyMapper scheduleStrategyMapper,
                               IntelligentScheduleService intelligentScheduleService, CloudMgmtService cloudMgmtService,
                               IndicatorService indicatorService) {
        this.gatewayConfig = gatewayConfig;
        this.algorithmEngineService = algorithmEngineService;
        this.clusterInfoService = clusterInfoService;
        this.microServiceMapper = microServiceMapper;
        this.scaleStrategyMapper = scaleStrategyMapper;
        this.scheduleStrategyMapper = scheduleStrategyMapper;
        this.intelligentScheduleService = intelligentScheduleService;
        this.cloudMgmtService = cloudMgmtService;
        this.indicatorService = indicatorService;
    }

    @Override
    public void notifyClusterInfoByMigrateCreateResource(NotifyClusterInfoDTO notifyClusterInfoDTO) {
        // 1、进行迁移操作，发送请求到新集群部署
        // 2、删除原有集群下的微服务
        // 3、更新intelligent history
        // 4、更新部署信息表
        LOGGER.info("[intelligent-migrate]: get notify request from multi system, start to distribute and update, svcId={}", notifyClusterInfoDTO.getSvcId());

        distributeAndUpdate(notifyClusterInfoDTO.getSvcId(), Collections.singletonList(notifyClusterInfoDTO.tpDeployClusterPO()));
        // 直接设置为已优化
        intelligentScheduleService.updateNewSuggestCluster(notifyClusterInfoDTO.getSvcId(), Collections.singletonList(notifyClusterInfoDTO.toIntelligentClusterInfo()));

    }

    @Override
    public void intelligentScheduleCompare(String svcId) {

//        判断是否需要迁移：
//        同一个云商 同一个zone 同一个可用区，且resourceType为exist，这种情况下不需要迁移，其余都需要迁移
//
//        迁移流程：
//        1、resourceType为exist，直接发送请求到算法引擎进行部署
//        2、resourceType为add/create，先发送创建虚机的请求到集群控制台，集群控制台创建完成后，回调应用管理，应用管理再发送请求到算法引擎进行部署
        //  判断是否需要迁移
        // 1、调用算法
        // 2、比较，是否与之前不同
        // 2.1 相同，无需迁移
        // 2.2 不同，迁移
        // 2.2.1 先部署
        // 2.2.2 再删除

        // 新算法结果
        DeployPolicyCalcResV2 resV2 = calAlgDeployClusterInfo(svcId);
        LOGGER.info("[intelligent-task]: get response from alg engine, response={}", JsonUtil.objectToJsonStr(resV2));
        List<AlgDeployClusterInfo> newInfo = resV2.getAlgDeployClusterInfos();
        AlgDeployClusterInfo newAlgInfo = newInfo.stream()
                .filter(alg -> resV2.getRecommendCloud().equals(alg.getProviderName()))
                .findFirst().orElse(null);
        if (Objects.isNull(newAlgInfo)) {
            LOGGER.error("alg return null algDeployClusterInfo, svcId={}", svcId);
            return;
        }
        ClusterDetail newDetail = newAlgInfo.getClusterDetails().get(0);

        // 旧策略算法结果
        ScheduleStrategyPO oldSchedule = scheduleStrategyMapper.selectByServiceId(svcId);
        List<AlgDeployClusterInfo> oldInfo = oldSchedule.getAlgDeployClusterInfos();
        // 取出当前部署集群的信息与新计算的进行比较
        List<DeployClusterPO> deployClusterPOS = clusterInfoService.getDeployClusterBySvcId(svcId);

        boolean needMigrate = true;

        for (DeployClusterPO deployClusterPO : deployClusterPOS) {
            AlgDeployClusterInfo tempInfo = oldInfo.stream()
                    .filter(alg -> deployClusterPO.getProviderName().equals(alg.getProviderName()))
                    .findFirst().orElse(null);
            if (Objects.isNull(tempInfo)) {
                continue;
            }
            // 固定为1个
            ClusterDetail tempDetail = tempInfo.getClusterDetails().get(0);

            if (tempInfo.getProviderName().equals(newAlgInfo.getProviderName()) &&
                    tempDetail.getRegionId().equals(newDetail.getRegionId()) &&
                    tempDetail.getZoneId().equals(newDetail.getZoneId()) &&
                    ResourceTypeEnum.EXIST.getType().equals(newAlgInfo.getResourceType())) {
                needMigrate = false;
                break;
            }
        }

        // 算法建议集群
        // 此时集群名称还没有，需要处理
        List<IntelligentClusterInfo> suggestClusterInfo = Collections.singletonList(newAlgInfo.toIntelligentClusterInfo());

        // 当前部署集群
        List<IntelligentClusterInfo> currentClusterInfo = deployClusterPOS.stream().map(DeployClusterPO::toIntelligentClusterInfo).collect(Collectors.toList());

        //  调用intelligentScheduleService

        intelligentScheduleService.saveIntelligentHistory(svcId, currentClusterInfo, suggestClusterInfo, needMigrate, resV2);
    }

    @Override
    public void migrateService(String svcId, List<IntelligentClusterInfo> suggestInfos, DeployPolicyCalcResV2 deployRes) {
        //        迁移流程：
        //        1、resourceType为exist，直接发送请求到算法引擎进行部署
        //        2、resourceType为add/create，先发送创建虚机的请求到集群控制台，集群控制台创建完成后，回调应用管理，应用管理再发送请求到算法引擎进行部署
        List<AlgDeployClusterInfo> newInfo = deployRes.getAlgDeployClusterInfos();
        AlgDeployClusterInfo newAlgInfo = newInfo.stream()
                .filter(alg -> deployRes.getRecommendCloud().equals(alg.getProviderName())
                        && deployRes.getRecommendAccountName().equals(alg.getAccountName()))
                .findFirst().orElse(null);
        if (Objects.isNull(newAlgInfo)) {
            LOGGER.error("alg return null algDeployClusterInfo, svcId={}", svcId);
            return;
        }

        if (ResourceTypeEnum.EXIST.getType().equals(newAlgInfo.getResourceType())) {
            LOGGER.info("[intelligent-migrate]: resource type is exist, send distribute request to engine, svcId={}", svcId);

            DeployClusterPO deployClusterPO = newAlgInfo.toDeployClusterPo();
            deployClusterPO.setServiceId(svcId);

            distributeAndUpdate(svcId, Collections.singletonList(deployClusterPO));
            // 更新本地schedule表记录中的alg_deploy_cluster_info, recommend, user_choose
            scheduleStrategyMapper.updateAlgInfoBySvcId(svcId, deployRes.getRecommendCloud(), deployRes.getUserChooseCloud(),
                    deployRes.getAlgDeployClusterInfos(), deployRes.getUserChooseAccountName(), deployRes.getRecommendAccountName());
            LOGGER.info("[intelligent-migrate]: update current schedule info, svcId={}", svcId);
        } else {
            LOGGER.info("[intelligent-migrate]: send request to multi system, svcId={}", svcId);
            // 发送集群控制台创建虚机
            // 集群控制台会异步回调，到时再发送请求到算法引擎部署
            List<ClusterDetail> clusterDetails = newAlgInfo.getClusterDetails();
            List<VmModel> vmModels = clusterDetails.stream()
                    .filter(cl -> deployRes.getRecommendCloud().equals(cl.getCloudType()))
                    .map(ClusterDetail::toVmModel).collect(Collectors.toList());
            if (vmModels.isEmpty()) {
                LOGGER.warn("alg cluster detail is empty, svcId={}", svcId);
                return;
            }
            CreateCloudParam createCloudParam = getCreateCloudParam(svcId, vmModels);
            CommentResultForCloud result = cloudMgmtService.createCloudResourceWithoutToken(createCloudParam);
            LOGGER.info("[intelligent-migrate]: get result from multi system for migrate, code={}", result.getCode());
        }

    }

    private void distributeAndUpdate(String svcId, List<DeployClusterPO> deployClusterPOS) {
        List<DeployClusterPO> currentCluster = clusterInfoService.getDeployClusterBySvcId(svcId);

        // 直接发送请求到算法引擎
        DistributeParamV2 distributeParamV2 = new DistributeParamV2();
        distributeParamV2.setServiceId(svcId);

        distributeParamV2.setClusters(deployClusterPOS);

        OperateService operateService = SpringUtil.getBean(OperateService.class);
        operateService.distributeV2(distributeParamV2);

        // 删除原有集群下的微服务
        OperateReq operateReq = new OperateReq();
        operateReq.setSvcId(svcId);
        operateReq.setOperation(OperateTypeEnum.DELETE_NO_RESPONSE.getType());
        algorithmEngineService.operate(operateReq);

        // 更新部署集群
        // 在distribute时已经插入了deployClusterInfo，所以此处需要更加集群名称删除
        for (DeployClusterPO deployClusterPO : currentCluster) {
            clusterInfoService.deleteDeployClusterBySvcIdAndClusterName(svcId, deployClusterPO.getClusterName());
        }
        LOGGER.info("[intelligent-migrate]: update current deploy cluster info, svcId={}", svcId);
    }

    private CreateCloudParam getCreateCloudParam(String svcId, List<VmModel> vmModels) {
        MicroServicePO s = microServiceMapper.selectMicroServiceById(svcId);

        ScheduleStrategyPO scheduleStrategyPO = scheduleStrategyMapper.selectByServiceId(svcId);
        String userChooseAccountName = scheduleStrategyPO.getUserChooseAccountName();
        String arch = scheduleStrategyPO.checkArch();

        ApplicationService applicationService = SpringUtil.getBean(ApplicationService.class);
        ApplicationPO applicationPO = applicationService.selectByAppId(s.getApplicationId());
        String cloudScope = applicationPO.getDeployResourceInfo().getCloudScope();

        CreateCloudParam createCloudParam = new CreateCloudParam();
        List<CloudVmModel> cloudVmModels = vmModels.stream().map(VmModel::toCloudVmModel).collect(Collectors.toList());
        createCloudParam.setVmModels(cloudVmModels);
        createCloudParam.setSvcId(IntelligentConstants.SEND_TO_CLOUD_MGT_PREFIX + svcId);
        createCloudParam.setType(StageTypeEnum.CLOUD_RESOURCE.getType());
        createCloudParam.setUserName(s.getUserName());
        createCloudParam.setCategory(s.getCategory());
        createCloudParam.setAppId(s.getApplicationId());
        createCloudParam.setArch(arch);
        createCloudParam.setAccountName(userChooseAccountName);
        createCloudParam.setCloudScope(cloudScope);

        return createCloudParam;
    }


    public DeployPolicyCalcResV2 calAlgDeployClusterInfo(String svcId) {
        MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(svcId);
        ScheduleStrategyPO scheduleStrategyPO = scheduleStrategyMapper.selectByServiceId(svcId);
        List<CommonScheduleDTO> dtos = Arrays.asList(scheduleStrategyPO.getSla(), scheduleStrategyPO.getCost(),
                scheduleStrategyPO.getEnergy(), scheduleStrategyPO.getLoad());
        List<DeployPolicyConfigV2> configV2s = dtos.stream().filter(Objects::nonNull).map(CommonScheduleDTO::toConfigV2).filter(Objects::nonNull).collect(Collectors.toList());

        DeployPolicyRequestV2 request = new DeployPolicyRequestV2();
        request.setSvcId(microServicePO.getId());
        request.setSvcName(microServicePO.getServiceName());
        request.setYaml(microServicePO.getYaml());
        request.setUserName(microServicePO.getUserName());
        request.setDeployPolicyConfigs(configV2s);

        CommentResultForEngine<DeployPolicyCalcResV2> result = algorithmEngineService.calculateDeployPolicyV2(request);
        DeployPolicyCalcResV2 res = result.getData();

        return res;
    }

    @Override
    public void addScheduleStrategy(List<ScheduleStrategyDTO> scheduleStrategyDTOs) {
        for (ScheduleStrategyDTO scheduleStrategyDTO : scheduleStrategyDTOs) {
            MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(scheduleStrategyDTO.getSvcId());
            // 判断权限
            if (!microServicePO.getUserName().equals(TokenUtils.getUserName())) {
                LOGGER.error("user {} has no permissions to add schedule strategy to microservice {}",
                        TokenUtils.getUserName(), microServicePO.getId());
                throw new JsonException(ResultCode.FORBIDDEN);
            }
            // 校验
            if (!scheduleStrategyDTO.verify()) {
                LOGGER.error("current schedule strategy is invalid, strategy={}", JsonUtil.objectToJsonStr(scheduleStrategyDTO));
                throw new JsonException(400, "所有策略相加需等于100且成本与能耗互斥");
            }

            ApplicationPO applicationPO = SpringUtil.getBean(ApplicationService.class).selectByAppId(microServicePO.getApplicationId());
            DeployResourceInfo deployResourceInfo = applicationPO.getDeployResourceInfo();

            String calculateType = SvcConstants.CPU;
            int batchSize = 0;
            if (scheduleStrategyDTO.getBusinessScene().getSvcType().equals(SvcTypeEnum.AI_TRAIN.getSvcType())) {
                calculateType = SvcConstants.GPU;
                if (Objects.isNull(scheduleStrategyDTO.getServiceModel())) {
                    // AI训练必须要配置服务模型调度参数
                    LOGGER.error("service model info is null, throw exception");
                    throw new JsonException(400, "AI训练必须要配置服务模型调度参数");
                }
                batchSize = scheduleStrategyDTO.getServiceModel().getBatchSize();
            }

            // V2.1 在此时生成指标实例
            // 先删除本地之前的指标实例
            indicatorService.deleteIndicatorCaseBySvcId(microServicePO.getId());
            // 再插入新的实例

            String type = microServicePO.getType();
            if (SvcConstants.GPU.equals(calculateType)) {
                // AI训练表示GPU，需要插入gpu指标，type值为Batchsize-8, Batchsize-16, Batchsize-32, Batchsize-64
                type = "Batchsize-" + batchSize;
            }

            batchInsertIndicatorCases(type, microServicePO);
            // 通知集群控制台，删除历史指标
            DeleteIndicatorHistoryParam deleteIndicatorHistoryParam = new DeleteIndicatorHistoryParam();
            deleteIndicatorHistoryParam.setSvcId(scheduleStrategyDTO.getSvcId());

            cloudMgmtService.deleteIndicatorHistory(deleteIndicatorHistoryParam);
            LOGGER.info("send delete indicator history request to multi, svcId={}", scheduleStrategyDTO.getSvcId());

            // 请求算法引擎
            // 算法引擎需要重新设计接口，适配包含所有策略的情况
            DeployPolicyRequestV2 request = new DeployPolicyRequestV2();
            request.setSvcId(microServicePO.getId());
            request.setSvcName(microServicePO.getServiceName());
            request.setYaml(microServicePO.getYaml());
            request.setUserName(TokenUtils.getUserName());
            request.setDeployPolicyConfigs(scheduleStrategyDTO.toDeployPolicyConfigV2s());
            request.setBatchSize(batchSize);
            request.setCalculateType(calculateType);
            request.setCommerceType(deployResourceInfo.getCloudScope());

            request.setRegionLocation(scheduleStrategyDTO.getLocation());

            // 默认使用通用价格
            request.setCostType(SvcConstants.COST_TYPE_COMMON);
            if (Objects.nonNull(scheduleStrategyDTO.getPrice()) && Objects.nonNull(scheduleStrategyDTO.getPrice().getParam())) {
                // 如果设置了成本算法，则使用成本算法内的值
                request.setCostType(scheduleStrategyDTO.getPrice().getParam().getCostType());
            }
            request.setAccountNames(deployResourceInfo.transToEngineCloudParam());

            CommentResultForEngine<DeployPolicyCalcResV2> result = algorithmEngineService.calculateDeployPolicyV2(request);
            DeployPolicyCalcResV2 res = result.getData();

            // 入库
            ScheduleStrategyPO oldPO = scheduleStrategyMapper.selectByServiceId(scheduleStrategyDTO.getSvcId());
            if (Objects.nonNull(oldPO)) {
                LOGGER.warn("service({}) has added schedule strategy, delete first and insert", scheduleStrategyDTO.getSvcId());
                scheduleStrategyMapper.deleteByServiceId(scheduleStrategyDTO.getSvcId());
            }

            ScheduleStrategyPO po = scheduleStrategyDTO.toPO();
            // 设置用户选择等字段
            po.setUserChooseCloud(res.getUserChooseCloud());
            po.setRecommendCloud(res.getRecommendCloud());
            po.setAlgDeployClusterInfos(res.getAlgDeployClusterInfos());
            po.setUserChooseAccountName(res.getUserChooseAccountName());
            po.setRecommendAccountName(res.getRecommendAccountName());
            scheduleStrategyMapper.insertScheduleStrategy(po);

        }
    }


    private void batchInsertIndicatorCases(String type, MicroServicePO microServicePO) {
        // 优化：批量插入需要分批
        // 参考monitor项目批量插入告警
        String appId = microServicePO.getApplicationId();
        List<IndicatorPO> indicatorPOS = indicatorService.getIndicatorByCategoryAndType(microServicePO.getCategory(), type);
        List<IndicatorCasePO> indicatorCasePOS = indicatorPOS.stream().map(indicatorPO -> {
            // 组装指标实例
            IndicatorCasePO indicatorCasePO = new IndicatorCasePO();
            // id
            indicatorCasePO.setId(IdUtil.simpleUUID());
            // 应用id
            indicatorCasePO.setAppId(appId);
            // 指标id
            indicatorCasePO.setIndicatorId(indicatorPO.getId());
            // 值
            indicatorCasePO.setValue(indicatorPO.getValue());
            // 微服务id
            indicatorCasePO.setSvcId(microServicePO.getId());
            // 微服务名称
            indicatorCasePO.setSvcName(microServicePO.getMicroServiceName());
            return indicatorCasePO;
        }).collect(Collectors.toList());
        boolean batchInsertResult = indicatorService.batchInsertIndicatorCases(indicatorCasePOS);
        if (!batchInsertResult) {
            LOGGER.error("insert indicator case error");
            throw new JsonException(500, "内部错误");
        }
    }

    @Override
    public void addScaleStrategy(List<ScaleStrategyDTO> scaleStrategyDTOS) {
        for (ScaleStrategyDTO strategyDTO : scaleStrategyDTOS) {
            // 判断调度策略是否添加完成
            ScheduleStrategyPO scheduleStrategyPO = scheduleStrategyMapper.selectByServiceId(strategyDTO.getSvcId());
            if (Objects.isNull(scheduleStrategyPO)) {
                LOGGER.error("can't find schedule strategy for service, svcId={}", strategyDTO.getSvcId());
                throw new JsonException(500, "请先进行调度策略配置");
            }


            MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(strategyDTO.getSvcId());
            // 判断权限
            if (!microServicePO.getUserName().equals(TokenUtils.getUserName())) {
                LOGGER.error("user {} has no permissions to add scale strategy to microservice {}",
                        TokenUtils.getUserName(), microServicePO.getId());
                throw new JsonException(ResultCode.FORBIDDEN);
            }
            List<ScaleStrategyPO> oldScalePOs = scaleStrategyMapper.selectByServiceId(strategyDTO.getSvcId());
            if (Objects.nonNull(oldScalePOs) && !oldScalePOs.isEmpty()) {
                LOGGER.warn("service({}) has added scale strategy, delete first and insert", strategyDTO.getSvcId());
                scaleStrategyMapper.deleteByServiceId(strategyDTO.getSvcId());
            }

            List<ScaleStrategyPO> pos = strategyDTO.toPOs();
            for (ScaleStrategyPO po : pos) {
                scaleStrategyMapper.insertScaleStrategy(po);
            }
        }
    }

    @Override
    public List<StrategyVO> getStrategyByAppId(String appId) {
        List<MicroServicePO> microServicePOS = microServiceMapper.selectMicroServiceByAppId(appId);
        ApplicationService applicationService = SpringUtil.getBean(ApplicationService.class);
        List<StrategyVO> result = new ArrayList<>();
        for (MicroServicePO microServicePO : microServicePOS) {
            StrategyVO strategyVO = new StrategyVO();
            // svc
            strategyVO.setSvcId(microServicePO.getId());
            strategyVO.setAppId(appId);
            strategyVO.setAppName(microServicePO.getApplicationName());
            strategyVO.setSvcName(microServicePO.getMicroServiceName());
            strategyVO.setSize(microServicePO.getSize());
            strategyVO.setProvider(microServicePO.getUserName());
            strategyVO.setStatus(String.valueOf(microServicePO.getStatus()));
            strategyVO.setCategory(microServicePO.getCategory());
            strategyVO.setUpdateTime(microServicePO.getUpdateTime());

            // scheduleStrategy
            ScheduleStrategyVO scheduleStrategyVO = null;
            ScheduleStrategyPO scheduleStrategyPO = scheduleStrategyMapper.selectByServiceId(microServicePO.getId());
            if (Objects.nonNull(scheduleStrategyPO)) {
                scheduleStrategyVO = scheduleStrategyPO.toVO();
            }
            strategyVO.setScheduleStrategy(scheduleStrategyVO);

            // scaleStrategy
            List<ScaleStrategyVO> scaleStrategyVOS = null;
            List<ScaleStrategyPO> scaleStrategyPOS = scaleStrategyMapper.selectByServiceId(microServicePO.getId());
            if (Objects.nonNull(scaleStrategyPOS) && !scaleStrategyPOS.isEmpty()) {
                scaleStrategyVOS = scaleStrategyPOS.stream().map(ScaleStrategyPO::toVO).collect(Collectors.toList());
            }

            // deplopyResourceInfo
            DeployResourceInfo deployResourceInfo = applicationService.selectByAppId(microServicePO.getApplicationId()).getDeployResourceInfo();
            strategyVO.setDeployResourceInfo(deployResourceInfo);


            strategyVO.setScaleStrategy(scaleStrategyVOS);

            result.add(strategyVO);
        }
        return result;
    }

    @Override
    public boolean deleteScheduleStrategy(List<String> ids) {
        boolean result = true;
        for (String id : ids) {
            result = result && scheduleStrategyMapper.deleteById(id) == 1;
        }
        return result;
    }

    @Override
    public boolean deleteScaleStrategy(List<String> ids) {
        boolean result = true;
        for (String id : ids) {
            result = result && scaleStrategyMapper.deleteById(id) == 1;
        }
        return result;
    }

    @Override
    public void updateUserChoose(UpdateUserChooseParam updateUserChooseParam) {
        MicroServicePO microServicePO = microServiceMapper.selectMicroServiceById(updateUserChooseParam.getSvcId());
        if (Objects.isNull(microServicePO)) {
            LOGGER.error("can't find service, svcId={}", updateUserChooseParam.getSvcId());
            throw new JsonException(404, "该微服务不存在");
        }
        // 获取调度策略
        ScheduleStrategyPO scheduleStrategy = scheduleStrategyMapper.selectByServiceId(updateUserChooseParam.getSvcId());
        if (Objects.isNull(scheduleStrategy)) {
            LOGGER.error("this service has no schedule strategy, svcId={}", updateUserChooseParam.getSvcId());
            throw new JsonException(404, "该微服务没有配置调度策略");
        }
        // 更新
        scheduleStrategyMapper.updateUserChooseCloudById(updateUserChooseParam.getSvcId(),
                updateUserChooseParam.getUserChooseCloud(), updateUserChooseParam.getUserChooseAccountName());
    }

    @Override
    public PageResult<MicroServiceVOV2> findByPage(QueryMicroServiceParam queryMicroServiceParam) {
        PageMethod.startPage(queryMicroServiceParam.getPageNum(), queryMicroServiceParam.getPageSize());
        List<MicroServicePO> svcPOs = microServiceMapper.selectDeployedMicroServiceByParamWithUser(queryMicroServiceParam, TokenUtils.getUserName());
        List<MicroServiceVOV2> vos = new ArrayList<>(svcPOs.size());
        for (MicroServicePO po : svcPOs) {
            MicroServiceVOV2 vo = po.toVOV2();

            // schedule
            ScheduleStrategyPO scheduleStrategyPO = scheduleStrategyMapper.selectByServiceId(po.getId());
            if (Objects.nonNull(scheduleStrategyPO)) {
                vo.setScheduleStrategy(scheduleStrategyPO.toVO());
            }

            // scale
            List<ScaleStrategyPO> scaleStrategyPOS = scaleStrategyMapper.selectByServiceId(po.getId());
            List<ScaleStrategyVO> scaleStrategyVOS = scaleStrategyPOS.stream().map(ScaleStrategyPO::toVO).collect(Collectors.toList());
            vo.setScaleStrategy(scaleStrategyVOS);

            // clusterInfos
            List<DeployClusterPO> clusterPOS = clusterInfoService.getDeployClusterBySvcId(po.getId());
            List<ClusterInfoVO> clusterInfoVOS = new ArrayList<>();
            Map<String, List<DeployClusterPO>> map = clusterPOS.stream().collect(Collectors.groupingBy(DeployClusterPO::getProviderName));
            for (Map.Entry<String, List<DeployClusterPO>> entry : map.entrySet()) {
                ClusterInfoVO clusterInfoVO = new ClusterInfoVO();
                clusterInfoVO.setManufacturer(entry.getKey());
                List<String> clusterNames = entry.getValue().stream().map(DeployClusterPO::getClusterName).collect(Collectors.toList());
                clusterInfoVO.setClusterNames(clusterNames);
                clusterInfoVOS.add(clusterInfoVO);
            }
            vo.setClusterInfos(clusterInfoVOS);

            // path
            List<String> pathWithGateway = vo.getPaths().stream().map(path -> gatewayConfig.getUrl() + "/" + path).collect(Collectors.toList());
            vo.setPaths(pathWithGateway);

            // intelligentHistorys
            List<IntelligentHistoryVO> historyVOS = intelligentScheduleService.getHistoryVOBySvcId(po.getId());
            vo.setIntelligentHistoryVOS(historyVOS);

            vos.add(vo);
        }
        PageInfo<MicroServicePO> realPageInfo = new PageInfo<>(svcPOs);
        PageInfo<MicroServiceVOV2> pageInfoToShow = new PageInfo<>(vos);
        PageUtils.setRealPageInfo(pageInfoToShow, realPageInfo);
        return PageUtils.getPageResult(pageInfoToShow);
    }

    @Override
    public void updateIntelligentParam(UpdateIntelligentDTO updateIntelligentDTO) {
        // 更新策略表
        scheduleStrategyMapper.updateIntelligentParam(updateIntelligentDTO);
        // 更新智能调度表
        intelligentScheduleService.updateIntelligent(updateIntelligentDTO);
    }

    @Override
    public void deleteIntelligentHistoryById(String id) {
        intelligentScheduleService.deleteHistoryById(id);
    }

    @Override
    @Transactional
    public void deleteStrategyBySvcId(String svcId) {
        scheduleStrategyMapper.deleteByServiceId(svcId);
        scaleStrategyMapper.deleteByServiceId(svcId);
    }

    @Override
    public void deleteIntelligentInfoBySvcId(String svcId) {
        intelligentScheduleService.deleteIntelligentInfoBySvcId(svcId);
    }
}
